Maialen Iturbide
manualRdatascience
http://r4ds.had.co.nz/index.html
Kaggle es una plataforma Web que reune a la mayor comunidad de data sciencetists del mundo: https://www.kaggle.com/
Kaggle ofrece:
La visualización se trata de crear “plots” o gráficos informativos que ayuden a entender los datos.
En esta sección utilizaremos el dataset de Iris de Fisher (también llamado dataset de Iris de Anderson) (https://en.wikipedia.org/wiki/Iris_flower_data_set).
El conjunto de datos contiene 50 muestras de cada una de tres especies de Iris (Iris setosa, Iris virginica e Iris versicolor). Se midieron cuatro rasgos de cada muestra: El largo y ancho de los sépalos y el largo y ancho de los pétalos. Basado en la combinación de estos cuatro rasgos, Fisher desarrolló un modelo discriminante lineal para distinguir entre una especie y otra.
Este dataset se encuentra en formato csv en kaggle (https://www.kaggle.com/uciml/iris).
Lo podemos leer (una vez descargado) en nuestra sesión de R con la función read.csv o read.table:
iris.kagg <- read.table(file = "data/Iris.csv", sep = ",", header = TRUE)
str(iris.kagg)
## 'data.frame': 150 obs. of 6 variables:
## $ Id : int 1 2 3 4 5 6 7 8 9 10 ...
## $ SepalLengthCm: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## $ SepalWidthCm : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
## $ PetalLengthCm: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
## $ PetalWidthCm : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
## $ Species : Factor w/ 3 levels "Iris-setosa",..: 1 1 1 1 1 1 1 1 1 1 ...
Este dataset también se encuentra disponible en el paquete datasets de R:
library(help = "datasets")
?iris
Podemos ver la estructura de iris con la función str():
str(iris)
## 'data.frame': 150 obs. of 5 variables:
## $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
## $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
## $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
## $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
Fijándonos en la estructura de ambos data.frames (objetos iris.kagg e iris), vemos que la versión de iris de kaggle tiene una variable más (ID).
La función de visualización básica de R es plot (?plot para acceder a la ayuda).
plot(iris$Sepal.Length, iris$Sepal.Width,
main="Edgar Anderson's Iris Data")
Visualicemos por ejemplo esta misma gráfica pero diferenciando con colores las diferentes especies de Iris. Para ello realizaremos una pequeña transformación de los datos en los pasos que se muestran a continuación.
La función levels() nos devuelve las especies que recoge el conjunto de datos:
levels(iris$Species)
## [1] "setosa" "versicolor" "virginica"
# Extraigo los datos que corresponden únicamente a la especie de Iris setosa
ind <- which(iris$Species == "setosa")
str(iris[ind, ])
## 'data.frame': 50 obs. of 5 variables:
## $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
## $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
## $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
## $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
# La función `subset` nos permite hacer lo mismo en un solo paso
setosa <- subset(iris, Species == "setosa")
str(setosa)
## 'data.frame': 50 obs. of 5 variables:
## $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
## $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
## $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
## $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
Si aplicamos subset() para cada una de las especies, mediante las funciones plot y points podemos diferenciarlas en un mismo gráfico:
versicolor <- subset(iris, Species == "versicolor")
virginica <- subset(iris, Species == "virginica")
plot(setosa$Sepal.Length, setosa$Sepal.Width, xlim = c(4, 8), ylim = c(2, 4.5))
points(virginica$Sepal.Length, virginica$Sepal.Width, col = "blue")
points(versicolor$Sepal.Length, versicolor$Sepal.Width, col = "red")
Para este caso concreto, la transformación de arriba no es necesaria, ya que podemos pasarle al argumento col la variable Species:
plot(iris$Sepal.Length, iris$Sepal.Width, col = iris$Species)
Existen librerías más potentes para la visualización de datos, por ejemplo, ggplot o lattice:
install.packages("lattice")
## Installing package into '/home/maialen/R/x86_64-pc-linux-gnu-library/3.5'
## (as 'lib' is unspecified)
library(lattice)
xyplot(Sepal.Width~Sepal.Length, data = iris)
xyplot(Sepal.Width~Sepal.Length|Species, data = iris)
xyplot(Sepal.Width~Sepal.Length, group = Species, data = iris, auto.key = TRUE)
xyplot(Petal.Width~Petal.Length, group = Species, data = iris,
auto.key = TRUE,
col = c("orange", "blue", "green"))
cloud(Petal.Width ~ Petal.Length * Sepal.Width, group = Species, data = iris, auto.key = TRUE)
splom(~iris[1:4], groups = Species, data = iris)
bwplot(Petal.Length~Species, data = iris)
#install.packages("tidyverse")
x <- c("ggplot2","dplyr","tidyr","readr","purrr","tibble","stringr","forcats")
install.packages(x)
#library(tidyverse)
library("ggplot2")
library("dplyr")
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library("tidyr")
library("readr")
library("purrr")
library("tibble")
library("stringr")
library("forcats")
La librería tidyverse carga a su vez las siguientes librerías o paquetes: * ggplot2, para visualizar datos. * dplyr, para manipular datos. * tidyr, para ordenar datos. * readr, para importar datos. * purrr, para programar funciones. * tibble, para tibbles, una versión moderna de los data.frames. * stringr, para cadenas de caracteres (character strings). * forcats, para factores.
En el siguiente ejemplo utilizamos ggplot() (paquete ggplot2) para visualizar los datos de iris.
Se comienza una gráfica con la función ggplot(), que crea un sistema de coordenadas al que se pueden agregar capas con el operador +. ggplot(data = mpg) crea un gráfico vacío y se completa, en este ejemplo, con otra capa de puntos, la generada por la función geom_point:
ggplot(data = iris) +
geom_point(mapping = aes(x = Petal.Width, y = Petal.Length))
ggplot(data = iris, aes(Species, Petal.Length)) +
geom_boxplot()
# tenemos la opción de convertir el data.frame a tibble
iris <- as_tibble(iris)
De aquí en adelante utilizaremos el dataset mpg incluido en el paquete ggplot2:
data(package = "ggplot2")
Para asociar un parámetro estético a una variable añadimos el nombre de ese parámetro (o argumento) en aes().
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy, color = class))
Los colores revelan que muchos de los puntos inusuales (rojo) son coches de dos plazas. A primeras, nadie diría que un coche de este tipo es híbrido… ¡son coches deportivos! que tienen motores grandes como los SUV y las Pickup, pero son pequeños, lo que mejora su consumo de combustible.
ggplot(mpg, aes(x = displ, y = hwy, color = class, shape= cty > 20)) +
geom_point()
Otra estrategia útil para diferenciar grupos de puntos es utilizar facet_wrap() como una capa de ggplot más.
ggplot(data = mpg) +
geom_point(mapping = aes(x = displ, y = hwy)) +
facet_wrap(~class, nrow = 2)
La visualización es una herramienta importante para la generación de información, pero es raro obtener los datos en la forma en la que se necesita. A menudo, habrá que crear nuevas variables o resúmenes, o tal vez solo cambiar el nombre de las variables o reordenar las observaciones…. para que sea más fácil trabajar con los datos.
Continuando con el uso de los paquetes de tidyverse, utilizaremos el paquete dplyr para transformar el dataset flights (flights departing New York City in 2013) que encontraréis en el subdirectorio “data” como un archivo de R (.rda). Para cargar flights en nuestra sesión utilizamos la función load.
load("data/flights.rda")
str(flights)
## Classes 'tbl_df', 'tbl' and 'data.frame': 336776 obs. of 19 variables:
## $ year : int 2013 2013 2013 2013 2013 2013 2013 2013 2013 2013 ...
## $ month : int 1 1 1 1 1 1 1 1 1 1 ...
## $ day : int 1 1 1 1 1 1 1 1 1 1 ...
## $ dep_time : int 517 533 542 544 554 554 555 557 557 558 ...
## $ sched_dep_time: int 515 529 540 545 600 558 600 600 600 600 ...
## $ dep_delay : num 2 4 2 -1 -6 -4 -5 -3 -3 -2 ...
## $ arr_time : int 830 850 923 1004 812 740 913 709 838 753 ...
## $ sched_arr_time: int 819 830 850 1022 837 728 854 723 846 745 ...
## $ arr_delay : num 11 20 33 -18 -25 12 19 -14 -8 8 ...
## $ carrier : chr "UA" "UA" "AA" "B6" ...
## $ flight : int 1545 1714 1141 725 461 1696 507 5708 79 301 ...
## $ tailnum : chr "N14228" "N24211" "N619AA" "N804JB" ...
## $ origin : chr "EWR" "LGA" "JFK" "JFK" ...
## $ dest : chr "IAH" "IAH" "MIA" "BQN" ...
## $ air_time : num 227 227 160 183 116 150 158 53 140 138 ...
## $ distance : num 1400 1416 1089 1576 762 ...
## $ hour : num 5 5 5 5 6 5 6 6 6 6 ...
## $ minute : num 15 29 40 45 0 58 0 0 0 0 ...
## $ time_hour : POSIXct, format: "2013-01-01 05:00:00" "2013-01-01 05:00:00" ...
Las cinco funciones clave de dplyr que te permiten resolver la gran mayoría de los problemas de manipulación de datos:
Mediante el uso de los operadores comparativos: >, >=, <, <=, != (no igual), == (igual)
jan1 <- filter(flights, month == 1, day == 1)
str(jan1)
## Classes 'tbl_df', 'tbl' and 'data.frame': 842 obs. of 19 variables:
## $ year : int 2013 2013 2013 2013 2013 2013 2013 2013 2013 2013 ...
## $ month : int 1 1 1 1 1 1 1 1 1 1 ...
## $ day : int 1 1 1 1 1 1 1 1 1 1 ...
## $ dep_time : int 517 533 542 544 554 554 555 557 557 558 ...
## $ sched_dep_time: int 515 529 540 545 600 558 600 600 600 600 ...
## $ dep_delay : num 2 4 2 -1 -6 -4 -5 -3 -3 -2 ...
## $ arr_time : int 830 850 923 1004 812 740 913 709 838 753 ...
## $ sched_arr_time: int 819 830 850 1022 837 728 854 723 846 745 ...
## $ arr_delay : num 11 20 33 -18 -25 12 19 -14 -8 8 ...
## $ carrier : chr "UA" "UA" "AA" "B6" ...
## $ flight : int 1545 1714 1141 725 461 1696 507 5708 79 301 ...
## $ tailnum : chr "N14228" "N24211" "N619AA" "N804JB" ...
## $ origin : chr "EWR" "LGA" "JFK" "JFK" ...
## $ dest : chr "IAH" "IAH" "MIA" "BQN" ...
## $ air_time : num 227 227 160 183 116 150 158 53 140 138 ...
## $ distance : num 1400 1416 1089 1576 762 ...
## $ hour : num 5 5 5 5 6 5 6 6 6 6 ...
## $ minute : num 15 29 40 45 0 58 0 0 0 0 ...
## $ time_hour : POSIXct, format: "2013-01-01 05:00:00" "2013-01-01 05:00:00" ...
day1 <- filter(flights, month != 2, day == 1)
ggplot(day1, aes(x = month, y = dep_delay, group = month)) +
geom_boxplot(width=0.6, na.rm = TRUE)
month2 <- filter(flights, month == 5 | month == 7, day == 1)
ggplot(month2, aes(x = month, y = dep_delay, group = month)) +
geom_boxplot(width=0.6, na.rm = TRUE)
bydate <- arrange(flights, year, month, day)
bydelay <- arrange(flights, desc(dep_delay))
ggplot(flights) +
geom_point(aes(1:nrow(flights), dep_delay)) +
geom_point(aes(1:nrow(flights), bydelay$dep_delay), color = "red")
## Warning: Removed 8255 rows containing missing values (geom_point).
## Warning: Removed 8255 rows containing missing values (geom_point).
# Seleccionar por el nombre de la columna
print(select(flights, year, month, day))
## # A tibble: 336,776 x 3
## year month day
## <int> <int> <int>
## 1 2013 1 1
## 2 2013 1 1
## 3 2013 1 1
## 4 2013 1 1
## 5 2013 1 1
## 6 2013 1 1
## 7 2013 1 1
## 8 2013 1 1
## 9 2013 1 1
## 10 2013 1 1
## # … with 336,766 more rows
# Seleccionar todas las columnas entre "year" y "day"
print(select(flights, year:day))
## # A tibble: 336,776 x 3
## year month day
## <int> <int> <int>
## 1 2013 1 1
## 2 2013 1 1
## 3 2013 1 1
## 4 2013 1 1
## 5 2013 1 1
## 6 2013 1 1
## 7 2013 1 1
## 8 2013 1 1
## 9 2013 1 1
## 10 2013 1 1
## # … with 336,766 more rows
# Seleccionar todas las columnas excepto las que están entre "year" y "day"
print(select(flights, -(year:day)))
## # A tibble: 336,776 x 16
## dep_time sched_dep_time dep_delay arr_time sched_arr_time arr_delay
## <int> <int> <dbl> <int> <int> <dbl>
## 1 517 515 2 830 819 11
## 2 533 529 4 850 830 20
## 3 542 540 2 923 850 33
## 4 544 545 -1 1004 1022 -18
## 5 554 600 -6 812 837 -25
## 6 554 558 -4 740 728 12
## 7 555 600 -5 913 854 19
## 8 557 600 -3 709 723 -14
## 9 557 600 -3 838 846 -8
## 10 558 600 -2 753 745 8
## # … with 336,766 more rows, and 10 more variables: carrier <chr>,
## # flight <int>, tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>,
## # distance <dbl>, hour <dbl>, minute <dbl>, time_hour <dttm>
Hya una serie de funciones “helper” que pueden utilizarse dentro de la función select():
starts_with("abc")
ends_with("xyz")
contains("ijk")
matches("(.)\\1")
num_range("x", 1:3)
flight_times <- select(flights, ends_with("time"))
str(flight_times)
## Classes 'tbl_df', 'tbl' and 'data.frame': 336776 obs. of 5 variables:
## $ dep_time : int 517 533 542 544 554 554 555 557 557 558 ...
## $ sched_dep_time: int 515 529 540 545 600 558 600 600 600 600 ...
## $ arr_time : int 830 850 923 1004 812 740 913 709 838 753 ...
## $ sched_arr_time: int 819 830 850 1022 837 728 854 723 846 745 ...
## $ air_time : num 227 227 160 183 116 150 158 53 140 138 ...
Otra función “helper” muy útil es everything()
df <- select(flights, time_hour, air_time, everything())
str(df)
## Classes 'tbl_df', 'tbl' and 'data.frame': 336776 obs. of 19 variables:
## $ time_hour : POSIXct, format: "2013-01-01 05:00:00" "2013-01-01 05:00:00" ...
## $ air_time : num 227 227 160 183 116 150 158 53 140 138 ...
## $ year : int 2013 2013 2013 2013 2013 2013 2013 2013 2013 2013 ...
## $ month : int 1 1 1 1 1 1 1 1 1 1 ...
## $ day : int 1 1 1 1 1 1 1 1 1 1 ...
## $ dep_time : int 517 533 542 544 554 554 555 557 557 558 ...
## $ sched_dep_time: int 515 529 540 545 600 558 600 600 600 600 ...
## $ dep_delay : num 2 4 2 -1 -6 -4 -5 -3 -3 -2 ...
## $ arr_time : int 830 850 923 1004 812 740 913 709 838 753 ...
## $ sched_arr_time: int 819 830 850 1022 837 728 854 723 846 745 ...
## $ arr_delay : num 11 20 33 -18 -25 12 19 -14 -8 8 ...
## $ carrier : chr "UA" "UA" "AA" "B6" ...
## $ flight : int 1545 1714 1141 725 461 1696 507 5708 79 301 ...
## $ tailnum : chr "N14228" "N24211" "N619AA" "N804JB" ...
## $ origin : chr "EWR" "LGA" "JFK" "JFK" ...
## $ dest : chr "IAH" "IAH" "MIA" "BQN" ...
## $ distance : num 1400 1416 1089 1576 762 ...
## $ hour : num 5 5 5 5 6 5 6 6 6 6 ...
## $ minute : num 15 29 40 45 0 58 0 0 0 0 ...
Además de seleccionar conjuntos de columnas existentes, a menudo es útil agregar nuevas columnas que son funciones de columnas existentes. Ese es el trabajo de mutate().
mutate() siempre agrega nuevas columnas al final de su conjunto de datos, por lo que utilizaremos un subconjunto de fights (usando select()) para que podamos ver las nuevas variables.
flights_sml <- select(flights,
year:day,
ends_with("delay"),
distance,
air_time
)
mutate(flights_sml,
gain = dep_delay - arr_delay,
speed = distance / air_time * 60
)
## # A tibble: 336,776 x 9
## year month day dep_delay arr_delay distance air_time gain speed
## <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2013 1 1 2 11 1400 227 -9 370.
## 2 2013 1 1 4 20 1416 227 -16 374.
## 3 2013 1 1 2 33 1089 160 -31 408.
## 4 2013 1 1 -1 -18 1576 183 17 517.
## 5 2013 1 1 -6 -25 762 116 19 394.
## 6 2013 1 1 -4 12 719 150 -16 288.
## 7 2013 1 1 -5 19 1065 158 -24 404.
## 8 2013 1 1 -3 -14 229 53 11 259.
## 9 2013 1 1 -3 -8 944 140 5 405.
## 10 2013 1 1 -2 8 733 138 -10 319.
## # … with 336,766 more rows
¿Qué ocurre con los NA del final?
Trabajar con los datos proporcionados por los paquetes de R es una excelente manera de aprender las herramientas de data science, pero en algún momento necesitaréis comenzar a trabajar con vuestros propios datos.
Utilizaremos el paquete readr, que es también parte de tidyverse.
La mayoría de las funciones de lectura convierten archivos planos en data frames:
read_csv() lee archivos delimitados por comas, read_csv2() lee archivos separados por punto y coma, read_tsv() lee archivos delimitados por tabulaciones, y read_delim() lee archivos con cualquier delimitador.
read_fwf() lee archivos de ancho fijo. Puede especificar campos por su ancho con fwf_widths() o su posición con fwf_positions(). read_table() lee una variación común de archivos de ancho fijo donde las columnas están separadas por espacios en blanco.
read_log() reads Apache style log files (ver https://www.screamingfrog.co.uk/an-seos-guide-to-apache-log-files/)
iris <- read_csv("data/Iris.csv")
## Parsed with column specification:
## cols(
## Id = col_double(),
## SepalLengthCm = col_double(),
## SepalWidthCm = col_double(),
## PetalLengthCm = col_double(),
## PetalWidthCm = col_double(),
## Species = col_character()
## )
str(iris)
## Classes 'spec_tbl_df', 'tbl_df', 'tbl' and 'data.frame': 150 obs. of 6 variables:
## $ Id : num 1 2 3 4 5 6 7 8 9 10 ...
## $ SepalLengthCm: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
## $ SepalWidthCm : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
## $ PetalLengthCm: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
## $ PetalWidthCm : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
## $ Species : chr "Iris-setosa" "Iris-setosa" "Iris-setosa" "Iris-setosa" ...
## - attr(*, "spec")=
## .. cols(
## .. Id = col_double(),
## .. SepalLengthCm = col_double(),
## .. SepalWidthCm = col_double(),
## .. PetalLengthCm = col_double(),
## .. PetalWidthCm = col_double(),
## .. Species = col_character()
## .. )
También podemos pasar a read_csv un csv que generemos “al vuelo” en R:
read_csv("a,b,c
1,2,3
4,5,6")
## # A tibble: 2 x 3
## a b c
## <dbl> <dbl> <dbl>
## 1 1 2 3
## 2 4 5 6
A veces hay algunas líneas de metadatos en la parte superior del archivo: * El argumento skip = n se usa para omitir las primeras n líneas. * El argumento comment = "#" se usa para eliminar todas las líneas que comienzan con (por ejemplo #)
read_csv("The first line of metadata
The second line of metadata
x,y,z
1,2,3", skip = 2)
## # A tibble: 1 x 3
## x y z
## <dbl> <dbl> <dbl>
## 1 1 2 3
read_csv("# A comment I want to skip
x,y,z
1,2,3", comment = "#")
## # A tibble: 1 x 3
## x y z
## <dbl> <dbl> <dbl>
## 1 1 2 3
Es posible que los datos no tengan nombres de columna. Puedes usar col_names = FALSE. (\n se puede usar para agregar una nueva línea).
read_csv("1,2,3\n4,5,6", col_names = FALSE)
## # A tibble: 2 x 3
## X1 X2 X3
## <dbl> <dbl> <dbl>
## 1 1 2 3
## 2 4 5 6
Puedes pasar a col_names un vector de caracteres que se usará como nombres de columna:
read_csv("1,2,3\n4,5,6", col_names = c("x", "y", "z"))
## # A tibble: 2 x 3
## x y z
## <dbl> <dbl> <dbl>
## 1 1 2 3
## 2 4 5 6
El argumento na se usa para especificar qué valor (o valores) del archivo son “missing values”:
read_csv("a,b,c\n1,2,.", na = ".")
## # A tibble: 1 x 3
## a b c
## <dbl> <dbl> <lgl>
## 1 1 2 NA
Las principales ventajas de read_csv frente a read.csv (de base de R) son: * Es más rápido. * Importa los datos a un objeto de clase tibble. De manera que… - No convierte los “character” a “factor” for defecto - No usa nombres de filas - No transforma los nombres de columna
¿Qúe función de importación utilizarías para un archivo separado por “|” (e.g. “a|b|c1|2|3”)? Escribe un ejemplo a continuación:
Identifica qué está mal en los siguientes archivos CSV y corrígelo:
read_csv("a,b\n1,2,3\n4,5,6")
## Warning: 2 parsing failures.
## row col expected actual file
## 1 -- 2 columns 3 columns literal data
## 2 -- 2 columns 3 columns literal data
## # A tibble: 2 x 2
## a b
## <dbl> <dbl>
## 1 1 2
## 2 4 5
read_csv("a;b\n1;3")
## # A tibble: 1 x 1
## `a;b`
## <chr>
## 1 1;3
readr incluye tres funciones útiles para escribir datos en disco: write_csv(), write_delim() write_tsv()
Exporta el dataset flights al directorio que quieras (utiliza ?write_csv como ayuda).
# write_...
A veces nos tenemos que enfrentar a datasets desordenados y complejos. El paquete tidyr ofrece herramientas que ayudan a ordenar datos. Los datos que utilizaremos en esta sección se incluyen en el paquete tidyr (e.g. table1, table2, …)
table1
## # A tibble: 6 x 4
## country year cases population
## <chr> <int> <int> <int>
## 1 Afghanistan 1999 745 19987071
## 2 Afghanistan 2000 2666 20595360
## 3 Brazil 1999 37737 172006362
## 4 Brazil 2000 80488 174504898
## 5 China 1999 212258 1272915272
## 6 China 2000 213766 1280428583
table2
## # A tibble: 12 x 4
## country year type count
## <chr> <int> <chr> <int>
## 1 Afghanistan 1999 cases 745
## 2 Afghanistan 1999 population 19987071
## 3 Afghanistan 2000 cases 2666
## 4 Afghanistan 2000 population 20595360
## 5 Brazil 1999 cases 37737
## 6 Brazil 1999 population 172006362
## 7 Brazil 2000 cases 80488
## 8 Brazil 2000 population 174504898
## 9 China 1999 cases 212258
## 10 China 1999 population 1272915272
## 11 China 2000 cases 213766
## 12 China 2000 population 1280428583
table3
## # A tibble: 6 x 3
## country year rate
## * <chr> <int> <chr>
## 1 Afghanistan 1999 745/19987071
## 2 Afghanistan 2000 2666/20595360
## 3 Brazil 1999 37737/172006362
## 4 Brazil 2000 80488/174504898
## 5 China 1999 212258/1272915272
## 6 China 2000 213766/1280428583
table4a
## # A tibble: 3 x 3
## country `1999` `2000`
## * <chr> <int> <int>
## 1 Afghanistan 745 2666
## 2 Brazil 37737 80488
## 3 China 212258 213766
table4b
## # A tibble: 3 x 3
## country `1999` `2000`
## * <chr> <int> <int>
## 1 Afghanistan 19987071 20595360
## 2 Brazil 172006362 174504898
## 3 China 1272915272 1280428583
Todas estas tablas son representaciones del mismo conjunto de datos subyacente, pero no son igualmente fáciles de usar. Nuestro objetivo es obtener un conjunto de datos ordenado.
Hay tres reglas que cumple un CONJUNTO DE DATOS ORDENADO:
En este ejemplo, únicamente table1 está ordenada. Es la única representación donde cada columna es una variable.
# Añadimos la variable rate (rate per 10,000)
mutate(table1, rate = cases / population * 10000)
## # A tibble: 6 x 5
## country year cases population rate
## <chr> <int> <int> <int> <dbl>
## 1 Afghanistan 1999 745 19987071 0.373
## 2 Afghanistan 2000 2666 20595360 1.29
## 3 Brazil 1999 37737 172006362 2.19
## 4 Brazil 2000 80488 174504898 4.61
## 5 China 1999 212258 1272915272 1.67
## 6 China 2000 213766 1280428583 1.67
gather(): Un problema común es un conjunto de datos donde algunos de los nombres de columnas no son nombres de variables, sino valores de una variable, como ocurre en table4a y table4b.table4a
## # A tibble: 3 x 3
## country `1999` `2000`
## * <chr> <int> <int>
## 1 Afghanistan 745 2666
## 2 Brazil 37737 80488
## 3 China 212258 213766
table4b
## # A tibble: 3 x 3
## country `1999` `2000`
## * <chr> <int> <int>
## 1 Afghanistan 19987071 20595360
## 2 Brazil 172006362 174504898
## 3 China 1272915272 1280428583
tidy4a <- gather(table4a, `1999`, `2000`, key = "year", value = "cases")
tidy4a
## # A tibble: 6 x 3
## country year cases
## <chr> <chr> <int>
## 1 Afghanistan 1999 745
## 2 Brazil 1999 37737
## 3 China 1999 212258
## 4 Afghanistan 2000 2666
## 5 Brazil 2000 80488
## 6 China 2000 213766
tidy4b <- gather(table4b, `1999`, `2000`, key = "year", value = "population")
tidy4b
## # A tibble: 6 x 3
## country year population
## <chr> <chr> <int>
## 1 Afghanistan 1999 19987071
## 2 Brazil 1999 172006362
## 3 China 1999 1272915272
## 4 Afghanistan 2000 20595360
## 5 Brazil 2000 174504898
## 6 China 2000 1280428583
Utilizamos la función left_join() de dplyr para combinar table4a y table4b:
left_join(tidy4a, tidy4b)
## Joining, by = c("country", "year")
## # A tibble: 6 x 4
## country year cases population
## <chr> <chr> <int> <int>
## 1 Afghanistan 1999 745 19987071
## 2 Brazil 1999 37737 172006362
## 3 China 1999 212258 1272915272
## 4 Afghanistan 2000 2666 20595360
## 5 Brazil 2000 80488 174504898
## 6 China 2000 213766 1280428583
spread(). A veces una observación está dispersa en varias filas (e.g. table2, una observación es un país en un año, pero cada observación se distribuye en dos filas).table2
## # A tibble: 12 x 4
## country year type count
## <chr> <int> <chr> <int>
## 1 Afghanistan 1999 cases 745
## 2 Afghanistan 1999 population 19987071
## 3 Afghanistan 2000 cases 2666
## 4 Afghanistan 2000 population 20595360
## 5 Brazil 1999 cases 37737
## 6 Brazil 1999 population 172006362
## 7 Brazil 2000 cases 80488
## 8 Brazil 2000 population 174504898
## 9 China 1999 cases 212258
## 10 China 1999 population 1272915272
## 11 China 2000 cases 213766
## 12 China 2000 population 1280428583
tidy2 <- spread(table2, key = type, value = count)
tidy2
## # A tibble: 6 x 4
## country year cases population
## <chr> <int> <int> <int>
## 1 Afghanistan 1999 745 19987071
## 2 Afghanistan 2000 2666 20595360
## 3 Brazil 1999 37737 172006362
## 4 Brazil 2000 80488 174504898
## 5 China 1999 212258 1272915272
## 6 China 2000 213766 1280428583
separate(). A veces podemos encontrarnos con una columna que contiene dos variables (e.g. table3, columna rate contiene las variables cases y population).table3
## # A tibble: 6 x 3
## country year rate
## * <chr> <int> <chr>
## 1 Afghanistan 1999 745/19987071
## 2 Afghanistan 2000 2666/20595360
## 3 Brazil 1999 37737/172006362
## 4 Brazil 2000 80488/174504898
## 5 China 1999 212258/1272915272
## 6 China 2000 213766/1280428583
separate(table3, rate, into = c("cases", "population"))
## # A tibble: 6 x 4
## country year cases population
## <chr> <int> <chr> <chr>
## 1 Afghanistan 1999 745 19987071
## 2 Afghanistan 2000 2666 20595360
## 3 Brazil 1999 37737 172006362
## 4 Brazil 2000 80488 174504898
## 5 China 1999 212258 1272915272
## 6 China 2000 213766 1280428583
tidy3 <- separate(table3, rate, into = c("cases", "population"), sep = "/")
unite(). Nos puede interesar combinar multiples variables en una única (e.g. para fechas)Hasta ahora, hemos ido ejecutando cada proceso con líneas de código independientes, asignando cada resultado provisional a una nueva variable. Por lo general, se suele construir un “pipe” gradualmente con %>%.
Por ejemplo:
data(iris)
hello <- iris %>%
group_by(Species) %>%
summarise(meanSL = mean(Sepal.Length), meanSW = mean(Sepal.Width),
meanPL = mean(Petal.Length), meanPW = mean(Petal.Width))
hello
## # A tibble: 3 x 5
## Species meanSL meanSW meanPL meanPW
## <fct> <dbl> <dbl> <dbl> <dbl>
## 1 setosa 5.01 3.43 1.46 0.246
## 2 versicolor 5.94 2.77 4.26 1.33
## 3 virginica 6.59 2.97 5.55 2.03
titanic <- read_csv("data/titanic.csv")
## Parsed with column specification:
## cols(
## PassengerId = col_double(),
## Survived = col_double(),
## Pclass = col_double(),
## Name = col_character(),
## Sex = col_character(),
## Age = col_double(),
## SibSp = col_double(),
## Parch = col_double(),
## Ticket = col_character(),
## Fare = col_double(),
## Cabin = col_character(),
## Embarked = col_character()
## )
str(titanic)
## Classes 'spec_tbl_df', 'tbl_df', 'tbl' and 'data.frame': 891 obs. of 12 variables:
## $ PassengerId: num 1 2 3 4 5 6 7 8 9 10 ...
## $ Survived : num 0 1 1 1 0 0 0 0 1 1 ...
## $ Pclass : num 3 1 3 1 3 3 1 3 3 2 ...
## $ Name : chr "Braund, Mr. Owen Harris" "Cumings, Mrs. John Bradley (Florence Briggs Thayer)" "Heikkinen, Miss. Laina" "Futrelle, Mrs. Jacques Heath (Lily May Peel)" ...
## $ Sex : chr "male" "female" "female" "female" ...
## $ Age : num 22 38 26 35 35 NA 54 2 27 14 ...
## $ SibSp : num 1 1 0 1 0 0 0 3 0 1 ...
## $ Parch : num 0 0 0 0 0 0 0 1 2 0 ...
## $ Ticket : chr "A/5 21171" "PC 17599" "STON/O2. 3101282" "113803" ...
## $ Fare : num 7.25 71.28 7.92 53.1 8.05 ...
## $ Cabin : chr NA "C85" NA "C123" ...
## $ Embarked : chr "S" "C" "S" "S" ...
## - attr(*, "spec")=
## .. cols(
## .. PassengerId = col_double(),
## .. Survived = col_double(),
## .. Pclass = col_double(),
## .. Name = col_character(),
## .. Sex = col_character(),
## .. Age = col_double(),
## .. SibSp = col_double(),
## .. Parch = col_double(),
## .. Ticket = col_character(),
## .. Fare = col_double(),
## .. Cabin = col_character(),
## .. Embarked = col_character()
## .. )
titanic %>%
select(-PassengerId, -Name, -Cabin, -Ticket) %>%
mutate(Sex = fct_recode(Sex,
"0" = "male",
"1" = "female"),
Embarked = fct_recode(Embarked,
"1" = "S",
"2" = "C",
"3" = "Q")
) %>%
mutate(Sex = as.integer(Sex),
Embarked = as.integer(Embarked),
Pclass = as.integer(Pclass),
Survived = as.integer(Survived)) %>%
filter(complete.cases(.)) %>%
cor() %>%
abs() %>%
levelplot(col.regions = c(gray.colors(5), rev(gray.colors(5))) , at = seq(-1, 1, 0.2))
(Dataset de ejemplo: Kaggle ML and Data Science Survey, 2017)
1.- Consulta el “overview” del dataset “Kaggle ML and Data Science Survey, 2017” de Kaggle (https://www.kaggle.com/kaggle/kaggle-survey-2017)
2.- Descárgalo y léelo en R. ¿Un único csv o varios?
3.- Echa un vistazo a los scripts de R markdown (notebooks con extensión “.rmd”) disponibles (pestaña kernels).
4.- Puedes elegir el que más te interese. Este, https://www.kaggle.com/kumarhalake/kaggle-survey-2017-graphical-exploration, es apropiado para visualizar datos. Puedes encontrar otro donde muestren cómo transformar los datos, por ejemplo, https://www.kaggle.com/mrisdal/dealing-with-dirty-data-on-the-job, o cómo ordenarlos (tidy).
5.- Reproduce alguno de los gráficos y pasos que se muestran en los notebooks de kaggle.